#include "utilsTest.h"
#include "dna.h"
#include <cstdlib>
#include <cstring>

#define A_FILL_LVL	10
#define B_FILL_LVL	3
#define MAX_DNA_STRING_SZ	20
/* Test init */
ListTest::ListTest()
{
}

void ListTest::setUp()
{
	this->lstA = new DnaSeq[MAX_DNA_STRING_SZ];
	this->refLstA = new DnaSeq[MAX_DNA_STRING_SZ];
	char* ptr=(char *)lstA;
	memset(ptr, 0, sizeof(DnaSeq)*MAX_DNA_STRING_SZ);

	this->lstB = new DnaSeq[MAX_DNA_STRING_SZ];
	this->refLstB = new DnaSeq[MAX_DNA_STRING_SZ];
	ptr=(char *)lstB;
	memset(ptr, 0, sizeof(DnaSeq)*MAX_DNA_STRING_SZ);
}

void ListTest::tearDown()
{
	delete this->lstA;
	delete this->refLstA;
	delete this->lstB;
	delete this->refLstB;
}


/* Testcases */
void ListTest::testMerge()
{
	/* A list is input list */
	for(int i=0; i<A_FILL_LVL; i++) {
		/* Set Used every other string */
		if (i%2 == 1) lstA[i].flag=1;
		else lstA[i].flag=0;
		/* Fill text */
		snprintf(lstA[i].nucl, sizeof(lstA[i].nucl), "%d", i & 0x3);
		lstA[i].len = sizeof(lstA[i].nucl);
	}
	/* Copy list A for later check */
	int cpyIdx = 0;
	for (int i=0; i < A_FILL_LVL; i++) {
		if (lstA[i].flag == 0) {
			memcpy(&refLstA[cpyIdx], &lstA[i], sizeof(lstA[i]));
			refLstA[cpyIdx].flag=0;
			cpyIdx++;
		}
	}

	/* B list is output list (i.e. no usedFlag set) */
	for(int i=0; i<B_FILL_LVL; i++) {
		/* Set none Used */
		lstB[i].flag=0;
		/* Fill text */
		snprintf(lstB[i].nucl, sizeof(lstB[i].nucl), "%d", (0x3-(i & 0x3)));
		lstB[i].len = sizeof(lstB[i].nucl);
	}
	/* Copy list B for later check */
	memcpy(refLstB, lstB, sizeof(lstB));

	/* Request to merge them */
	size_t sizeB=B_FILL_LVL;
	mergeLists(lstB, sizeB, lstA, A_FILL_LVL);

	/* Check if properly merged */
	/* Check size of B */
	CPPUNIT_ASSERT( sizeB == (B_FILL_LVL + A_FILL_LVL/2));

	/* Check that all flags are reset in destination list */
	bool allZeroFlag=true;
	for(int i=0; i<MAX_DNA_STRING_SZ; i++){
		if(lstB[i].flag!=0 ) allZeroFlag=false;
	}
	CPPUNIT_ASSERT( allZeroFlag==true );

	/* Check that first elements of B are initial ones */
	CPPUNIT_ASSERT( memcmp(lstB, refLstB, sizeof(refLstB)) == 0 );

	/* Check that following elements of B are unsued ones from A */
	CPPUNIT_ASSERT( memcmp(&lstB[B_FILL_LVL], refLstA, sizeof(refLstA)) == 0 );
}

void ListTest::testEmpty()
{

	/* Fill list */
	for(int i=0; i<A_FILL_LVL; i++) {
		/* Set Used every other string */
		if (i%2 == 0) lstA[i].flag=1;
		else lstA[i].flag=0;
		/* Fill text */
		snprintf(lstA[i].nucl, sizeof(lstA[i].nucl), "%d", i & 0x3);
		lstA[i].len = sizeof(lstA[i].nucl);
	}

	/* Request to empty it */
	emptyList(lstA, MAX_DNA_STRING_SZ);

	/* Check resulting list */
	for(int i=0; i<MAX_DNA_STRING_SZ; i++){
		CPPUNIT_ASSERT( lstA[i].flag==0 );
		CPPUNIT_ASSERT( lstA[i].len==0 );
		bool eqNucl=true;
		for (int j=0; j < sizeof(lstA[i].nucl); j++) {
			if (lstA[i].nucl[j] != (char)0) {
				eqNucl = false;
				break;
			}
		}
		CPPUNIT_ASSERT( eqNucl==true );
	}
}

/* Test init */
NuclTest::NuclTest()
{
}

void NuclTest::setUp()
{
}

void NuclTest::tearDown()
{
}

/* Testcases */
void NuclTest::testCompactFormat()
{
	int a = Nucl('A');
	int c = Nucl('C');
	int g = Nucl('G');
	int t = Nucl('T');
	int exception = 0;

	try {
		int f = Nucl('F');
	}
	catch (int e) {
		exception = e;
	}

	CPPUNIT_ASSERT( a == 0 );
	CPPUNIT_ASSERT( c == 1 );
	CPPUNIT_ASSERT( g == 2 );
	CPPUNIT_ASSERT( t == 3 );
	CPPUNIT_ASSERT( exception == 3 );
}

void NuclTest::testUncompactFormat()
{
	char a = Nucl(0);
	char c = Nucl(1);
	char g = Nucl(2);
	char t = Nucl(3);
	int exception = 0;

	try {
		char f = Nucl(5);
	}
	catch (int e) {
		exception = e;
	}

	CPPUNIT_ASSERT( a == 'A' );
	CPPUNIT_ASSERT( c == 'C' );
	CPPUNIT_ASSERT( g == 'G' );
	CPPUNIT_ASSERT( t == 'T' );
	CPPUNIT_ASSERT( exception == 2 );
}

void NuclTest::testArrayPos()
{
	int a = NUCL_ARRAY_POS(11);

	CPPUNIT_ASSERT( a == 2 );
}

void NuclTest::testCharPos()
{
	int a = NUCL_CHAR_POS(11);

	CPPUNIT_ASSERT( a == 3);
}

void NuclTest::testGetNucleotide()
{
	char s = (char ) 0x10;
	int i = GET_NUCLEOTIDE(s, 2);

	CPPUNIT_ASSERT( i == 1 );
}

void NuclTest::testSetNucleotide()
{
	char s = (char) 0xcf;

	s = SET_NUCLEOTIDE( s, 1, 2);

	CPPUNIT_ASSERT( s == (char) 0xdf );
}

void NuclTest::testDnaSeqConv2String()
{
	std::string refStr= "CACTAGATGTTGGTATGACGAAAATCCTCCGAACGGATCA";
	DnaSeq nuclS={0,40, {0xd1, 0xc8, 0xbe, 0xce, 0x92, 0x00, 0xd7, 0x25, 0xa4, 0x1c}};
	std::string str;

	conv2string(nuclS, str);

	CPPUNIT_ASSERT( strcmp(str.c_str(), refStr.c_str()) == 0 );
}


